"""
依赖注入装饰器

提供便捷的装饰器语法来标记可注入的类和依赖。
"""

import functools
from typing import Any, Type, TypeVar, Union, Optional, Callable
from .tokens import Token, create_token, InjectToken

T = TypeVar('T')


class Injectable:
    """
    可注入装饰器
    
    标记一个类为可注入的，允许依赖注入容器管理其实例。
    """
    
    def __init__(self, 
                 scope: str = "transient",
                 token: Optional[Union[str, Token]] = None,
                 lazy: bool = False):
        self.scope = scope
        self.token = token
        self.lazy = lazy
    
    def __call__(self, cls: Type[T]) -> Type[T]:
        """装饰类"""
        # 设置依赖注入元数据
        cls._di_injectable = True
        cls._di_scope = self.scope
        cls._di_lazy = self.lazy
        
        # 设置Token
        if self.token:
            if isinstance(self.token, str):
                cls._di_token = create_token(self.token)
            else:
                cls._di_token = self.token
        else:
            cls._di_token = create_token(cls)
        
        return cls


class Inject:
    """
    依赖注入标记
    
    用于标记构造函数参数或方法参数需要依赖注入。
    """
    
    def __init__(self, token: Union[str, Type, Token]):
        if isinstance(token, Token):
            self.token = token
        else:
            self.token = create_token(token)
    
    def __str__(self) -> str:
        return f"Inject({self.token})"
    
    def __repr__(self) -> str:
        return self.__str__()


class Singleton:
    """
    单例装饰器
    
    标记一个类为单例模式。
    """
    
    def __init__(self, token: Optional[Union[str, Token]] = None):
        self.token = token
    
    def __call__(self, cls: Type[T]) -> Type[T]:
        """装饰类为单例"""
        injectable = Injectable(scope="singleton", token=self.token)
        return injectable(cls)


class Transient:
    """
    瞬态装饰器
    
    标记一个类为瞬态模式（每次请求都创建新实例）。
    """
    
    def __init__(self, token: Optional[Union[str, Token]] = None):
        self.token = token
    
    def __call__(self, cls: Type[T]) -> Type[T]:
        """装饰类为瞬态"""
        injectable = Injectable(scope="transient", token=self.token)
        return injectable(cls)


class Lazy:
    """
    懒加载装饰器
    
    标记一个类为懒加载模式。
    """
    
    def __init__(self, 
                 scope: str = "singleton",
                 token: Optional[Union[str, Token]] = None):
        self.scope = scope
        self.token = token
    
    def __call__(self, cls: Type[T]) -> Type[T]:
        """装饰类为懒加载"""
        injectable = Injectable(scope=self.scope, token=self.token, lazy=True)
        return injectable(cls)


class Provides:
    """
    提供者装饰器
    
    标记一个方法为依赖提供者。
    """
    
    def __init__(self, 
                 token: Optional[Union[str, Type, Token]] = None,
                 scope: str = "transient"):
        self.token = token
        self.scope = scope
    
    def __call__(self, func: Callable) -> Callable:
        """装饰方法为提供者"""
        # 设置提供者元数据
        func._di_provider = True
        func._di_scope = self.scope
        
        # 设置Token
        if self.token:
            if isinstance(self.token, Token):
                func._di_token = self.token
            else:
                func._di_token = create_token(self.token)
        else:
            # 使用返回类型作为Token
            import inspect
            sig = inspect.signature(func)
            if sig.return_annotation != inspect.Signature.empty:
                func._di_token = create_token(sig.return_annotation)
            else:
                raise ValueError(f"提供者方法 {func.__name__} 必须指定返回类型或Token")
        
        return func


class PostConstruct:
    """
    构造后回调装饰器
    
    标记一个方法在对象构造完成后调用。
    """
    
    def __call__(self, func: Callable) -> Callable:
        """装饰方法为构造后回调"""
        func._di_post_construct = True
        return func


class PreDestroy:
    """
    销毁前回调装饰器
    
    标记一个方法在对象销毁前调用。
    """
    
    def __call__(self, func: Callable) -> Callable:
        """装饰方法为销毁前回调"""
        func._di_pre_destroy = True
        return func


class Qualifier:
    """
    限定符装饰器
    
    为依赖注入添加限定符，用于区分同一类型的不同实例。
    """
    
    def __init__(self, name: str):
        self.name = name
    
    def __call__(self, cls_or_func: Union[Type[T], Callable]) -> Union[Type[T], Callable]:
        """添加限定符"""
        if isinstance(cls_or_func, type):
            # 装饰类
            cls_or_func._di_qualifier = self.name
            return cls_or_func
        else:
            # 装饰方法
            cls_or_func._di_qualifier = self.name
            return cls_or_func


class Component:
    """
    组件装饰器
    
    标记一个类为组件，自动注册到依赖注入容器。
    """
    
    def __init__(self, 
                 name: Optional[str] = None,
                 scope: str = "singleton"):
        self.name = name
        self.scope = scope
    
    def __call__(self, cls: Type[T]) -> Type[T]:
        """装饰类为组件"""
        # 设置组件元数据
        cls._di_component = True
        cls._di_component_name = self.name or cls.__name__.lower()
        
        # 应用Injectable装饰器
        injectable = Injectable(scope=self.scope)
        return injectable(cls)


class Service:
    """
    服务装饰器
    
    标记一个类为服务组件。
    """
    
    def __init__(self, name: Optional[str] = None):
        self.name = name
    
    def __call__(self, cls: Type[T]) -> Type[T]:
        """装饰类为服务"""
        component = Component(name=self.name, scope="singleton")
        cls._di_service = True
        return component(cls)


class Repository:
    """
    仓储装饰器
    
    标记一个类为仓储组件。
    """
    
    def __init__(self, name: Optional[str] = None):
        self.name = name
    
    def __call__(self, cls: Type[T]) -> Type[T]:
        """装饰类为仓储"""
        component = Component(name=self.name, scope="singleton")
        cls._di_repository = True
        return component(cls)


class Controller:
    """
    控制器装饰器
    
    标记一个类为控制器组件。
    """
    
    def __init__(self, name: Optional[str] = None):
        self.name = name
    
    def __call__(self, cls: Type[T]) -> Type[T]:
        """装饰类为控制器"""
        component = Component(name=self.name, scope="singleton")
        cls._di_controller = True
        return component(cls)


# 便捷函数
def injectable(cls: Type[T] = None, *, 
               scope: str = "transient",
               token: Optional[Union[str, Token]] = None,
               lazy: bool = False) -> Union[Type[T], Callable[[Type[T]], Type[T]]]:
    """
    可注入装饰器的便捷函数形式
    
    支持两种使用方式：
    1. @injectable
    2. @injectable(scope="singleton")
    """
    def decorator(cls: Type[T]) -> Type[T]:
        return Injectable(scope=scope, token=token, lazy=lazy)(cls)
    
    if cls is None:
        # 带参数调用: @injectable(scope="singleton")
        return decorator
    else:
        # 无参数调用: @injectable
        return decorator(cls)


def singleton(cls: Type[T] = None, *, 
              token: Optional[Union[str, Token]] = None) -> Union[Type[T], Callable[[Type[T]], Type[T]]]:
    """
    单例装饰器的便捷函数形式
    """
    def decorator(cls: Type[T]) -> Type[T]:
        return Singleton(token=token)(cls)
    
    if cls is None:
        return decorator
    else:
        return decorator(cls)


def transient(cls: Type[T] = None, *, 
              token: Optional[Union[str, Token]] = None) -> Union[Type[T], Callable[[Type[T]], Type[T]]]:
    """
    瞬态装饰器的便捷函数形式
    """
    def decorator(cls: Type[T]) -> Type[T]:
        return Transient(token=token)(cls)
    
    if cls is None:
        return decorator
    else:
        return decorator(cls)


def component(cls: Type[T] = None, *, 
              name: Optional[str] = None,
              scope: str = "singleton") -> Union[Type[T], Callable[[Type[T]], Type[T]]]:
    """
    组件装饰器的便捷函数形式
    """
    def decorator(cls: Type[T]) -> Type[T]:
        return Component(name=name, scope=scope)(cls)
    
    if cls is None:
        return decorator
    else:
        return decorator(cls)


def service(cls: Type[T] = None, *, 
            name: Optional[str] = None) -> Union[Type[T], Callable[[Type[T]], Type[T]]]:
    """
    服务装饰器的便捷函数形式
    """
    def decorator(cls: Type[T]) -> Type[T]:
        return Service(name=name)(cls)
    
    if cls is None:
        return decorator
    else:
        return decorator(cls)


# 参数注入辅助函数
def inject(token: Union[str, Type, Token]) -> Inject:
    """创建注入标记"""
    return Inject(token)
